def fixed(input):
    pos = 0
    while pos < len(input) and input[pos] in " *":
        pos += 1

    return input[pos:]

def details(item):
    return (item.fileName, item.startPosition, item.name)

def quote_docstring(data):
    lines = data.split("\n")
    lines = [line.strip() for line in lines]
    while lines and not lines[0]:
        lines = lines[1:]
    while lines and not lines[-1]:
        lines = lines[:-1]
    text = "\\n".join(lines).strip()
    text = text.replace("\t", "\\t")
    text = text.replace('"', '\\"')
    return '"' + text + '"'

class DocstringFile(object):
    """
    Represents a single file
    """
    def __init__(self, filename):
        self.filename = filename
        self.items = set()
        self.ready = False

    def make_ready(self):
        self.ready = True

        content = open(self.filename)
        active_comment = False
        comment = None
        line_no = 0
        items = []
        for line in content:
            line_no += 1
            if active_comment:
                pos = line.find("*/")
                if pos == -1:
                    comment += fixed(line)
                else:
                    comment += fixed(line[:pos])
                    comment = quote_docstring(comment)
                    items.append( (line_no, comment) )
                    active_comment = False
            else:
                pos = line.find("/**")
                if pos != -1:
                    comment = line[pos+3:]
                    active_comment = True
                
        for item in self.items:
            line, col = item.startPosition
            items.append( (line, item) )

        items.sort()
        prev = None
        self.docstrings = {}
        for line, item in items:
            if not isinstance(item, basestring) and isinstance(prev, basestring):
                self.docstrings[details(item)] = prev
            prev = item



    def add(self, item):
        self.items.add(item)

    def request(self, item):
        if not self.ready:
            self.make_ready()
        return self.docstrings.get(details(item), None)

class DocstringSource(object):
    """
    This class is responsible for extracting docstrings from c++
    """

    def __init__(self, cm):
        """
        cm is a CodeModel object from the parser
        """

        self.files = {}
        self.explore(cm.globalNamespace)

    def request(self, item):
        the_file = self.files[item.fileName]
        return the_file.request(item)


    def explore(self, item):

        if item.fileName is not None:
            file_obj = self.files.setdefault(
                item.fileName, DocstringFile(item.fileName))
            file_obj.add(item)

        maps = ['classMap', 'functionMap', 'functionDefinitionMap', 'namespaceMap']
        for map_attr in maps:
            try:
                items = getattr(item, map_attr)
            except AttributeError:
                pass
            else:
                for value in items.values():
                    self.explore(value)
            
